#include "nemu.h"
#include <stdlib.h>
#include <time.h>

CPU_state cpu;

const char *regsl[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
const char *regsw[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
const char *regsb[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};

void reg_test() {
	srand(time(0));
	uint32_t sample[8];
	uint32_t eip_sample = rand();
	cpu.eip = eip_sample;

	int i;
	for(i = R_EAX; i <= R_EDI; i ++) {
		sample[i] = rand();
		reg_l(i) = sample[i];
		assert(reg_w(i) == (sample[i] & 0xffff));
	}

	assert(reg_b(R_AL) == (sample[R_EAX] & 0xff));
	assert(reg_b(R_AH) == ((sample[R_EAX] >> 8) & 0xff));
	assert(reg_b(R_BL) == (sample[R_EBX] & 0xff));
	assert(reg_b(R_BH) == ((sample[R_EBX] >> 8) & 0xff));
	assert(reg_b(R_CL) == (sample[R_ECX] & 0xff));
	assert(reg_b(R_CH) == ((sample[R_ECX] >> 8) & 0xff));
	assert(reg_b(R_DL) == (sample[R_EDX] & 0xff));
	assert(reg_b(R_DH) == ((sample[R_EDX] >> 8) & 0xff));

	assert(sample[R_EAX] == cpu.eax);
	assert(sample[R_ECX] == cpu.ecx);
	assert(sample[R_EDX] == cpu.edx);
	assert(sample[R_EBX] == cpu.ebx);
	assert(sample[R_ESP] == cpu.esp);
	assert(sample[R_EBP] == cpu.ebp);
	assert(sample[R_ESI] == cpu.esi);
	assert(sample[R_EDI] == cpu.edi);

	assert(eip_sample == cpu.eip);
}


void sreg_load(uint8_t sreg_id){
	
	//检查保护模式是否开启
	Assert(cpu.cr0.pe,"error:protect mode is not open!");
	
	//最高13位取出索引index
	uint16_t index = cpu.sreg[sreg_id].selector >> 3;
	//检查索引是否合法：索引*每个条目字节数(8字节)=大小，这个大小应小于段描述符表的最大大小limit
	Assert((index << 3) <= cpu.gdtr.limit,"error:segement selector index is out of the limit!");
	
	//求出段描述符的线性地址
	lnaddr_t seg_desc_lnaddr = cpu.gdtr.base + (index << 3);
	//根据线性地址将段描述符读出来，每次最多读32位
	sreg_desc->part1 = lnaddr_read(seg_desc_lnaddr, 4);
	sreg_desc->part2 = lnaddr_read(seg_desc_lnaddr + 4, 4);
	//检查段描述符是否有效
	Assert(sreg_desc->p == 1, "error:segement not exist!");
	
	//取出段的base
	uint32_t base = 0;
	//把拆开的三段base组合成原base
	base += ((uint32_t)sreg_desc->base1);
	base += ((uint32_t)sreg_desc->base2) << 16;
	base += ((uint32_t)sreg_desc->base3) << 24;
	//把base存到对应段寄存器中
	cpu.sreg[sreg_id].base = base;

	//取出段的limit
	uint32_t limit = 0;
	limit += ((uint32_t)sreg_desc->limit1);
	limit += ((uint32_t)sreg_desc->limit2) << 16;
	//G位为0的话，Limit高12位就填充0
	//G位为1的话，Limit低12位就填充F
	if (sreg_desc->g == 1) limit = (limit << 12) + (uint32_t)0xfff;
	//Log("limit:0x%X\n",limit);
	cpu.sreg[sreg_id].limit = limit;
}

